package com.beordie.version_2.aop.interceptor;

import com.beordie.version_2.aop.config.BODJoinPoint;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Date 2022/2/22 15:08
 * @Created 30500
 */
public class BODMethodInvocation implements BODJoinPoint {
    protected final Object proxy;
    protected final Object target;
    private final Class<?> targetClass;
    protected final Method method;
    protected Object[] arguments;
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    private Integer currentInterceptorIndex = -1;
    private Map<String, Object> userAttribute;

    public BODMethodInvocation(Object o, Object targetInstance, Method method, Object[] objects, Class targetClass, List<Object> chain) {
        this.proxy = o;
        this.target = targetInstance;
        this.targetClass = targetClass;
        this.method = method;
        this.arguments = objects;
        this.interceptorsAndDynamicMethodMatchers = chain;
        this.userAttribute = new HashMap<>();
    }

    public Object procced() throws Throwable{
        //  最后一个执行链调用自己
        if (this.interceptorsAndDynamicMethodMatchers == null
                || this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(this.target, this.arguments);
        }
        //  获取下一个执行
        Object o = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (o instanceof BODMethodInterceptor) {
            BODMethodInterceptor interceptor = (BODMethodInterceptor) o;
            return interceptor.invoke(this);
        } else {
            return procced();
        }
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public Object[] getArgument() {
        return this.arguments;
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public void setUserAttribute(String key, Object value) {
        this.userAttribute.put(key, value);
    }

    @Override
    public Object getUserAttribute(String key) {
        return this.userAttribute.get(key);
    }
}
